#ifndef CHATMANAGER_H
#define CHATMANAGER_H

#include <map>
#include <string>
#include <vector>

#include "PacketListener.h"

#include <filter/PacketFilter.h>

class Chat;
class ChatManagerListener;
class PacketCollector;
class PacketInterceptor;
class XMPPConnection;
class MessageListener;
class Message;
class Packet;

/**
 * The chat manager keeps track of references to all current chats. It will not hold any references
 * in memory on its own so it is neccesary to keep a reference to the chat object itself. To be
 * made aware of new chats, register a listener by calling {@link #addChatListener(ChatManagerListener)}.
 *
 * @author 
 */
class ChatManager {
public:
	ChatManager( XMPPConnection * connection) ;
	
    /**
     * Creates a new chat and returns it.
     *
     * @param userJID the user this chat is with.
     * @param listener the listener which will listen for new messages from this chat.
     * @return the created chat.
     */
    Chat* createChat( std::string & userJID, MessageListener * listener) ;
	
    /**
     * Creates a new chat using the specified thread ID, then returns it.
     * 
     * @param userJID the jid of the user this chat is with
     * @param thread the thread of the created chat.
     * @param listener the listener to add to the chat
     * @return the created chat.
     */
    Chat* createChat( std::string userJID, std::string thread, MessageListener * listener) ;
	
	Chat* getThreadChat( std::string thread) ;

    /**
     * Register a new listener with the ChatManager to recieve events related to chats.
     *
     * @param listener the listener.
     */
    void addChatListener( ChatManagerListener * listener) ;

    /**
     * Removes a listener, it will no longer be notified of new events related to chats.
     *
     * @param listener the listener that is being removed
     */
    void removeChatListener( ChatManagerListener * listener) ;
	
    /**
     * Returns an unmodifiable collection of all chat listeners currently registered with this
     * manager.
     *
     * @return an unmodifiable collection of all chat listeners currently registered with this
     * manager.
     */
    std::vector<ChatManagerListener*> getChatListeners(); 

	void sendMessage( Chat * chat, Message * message) ;
	
	PacketCollector * createPacketCollector( Chat * chat);
	
    /**
     * Adds an interceptor which intercepts any messages sent through chats.
     *
     * @param packetInterceptor the interceptor.
     */
    void addOutgoingMessageInterceptor( PacketInterceptor * packetInterceptor) ;
	void addOutgoingMessageInterceptor( PacketInterceptor * packetInterceptor, PacketFilter * filter) ;
private:
	class MPacketFilter : public PacketFilter {
	public:
		bool accept(Packet * packet);
	};

	class DeliverPacketListener : public PacketListener {
	public:
		DeliverPacketListener(ChatManager * m) : manager(m) {}
		void processPacket(Packet * packet);
	private:
		ChatManager * manager;
	};

    /**
     * Returns the next unique id. Each id made up of a short alphanumeric
     * prefix along with a unique numeric value.
     *
     * @return the next id.
     */
	static std::string nextID() ;


    /**
     * A prefix helps to make sure that ID's are unique across mutliple instances.
     */
	static std::string prefix;

    /**
     * Keeps track of the current increment, which is appended to the prefix to
     * forum a unique ID.
     */
	static long id;

	
    Chat * createChat(std::string userJID, std::string threadID, bool createdLocally) ;
	Chat * createChat(Message * message) ;
	Chat * getUserChat(std::string userJID) ;
	void deliverMessage(Chat * chat, Message * message) ;

    /**
     * Maps thread ID to chat.
     */
	std::map<std::string, Chat*> threadChats;
	
    /**
     * Maps jids to chats
     */
	std::map<std::string, Chat*> jidChats;
	std::vector<ChatManagerListener*> chatManagerListeners;
	std::map<PacketInterceptor*, PacketFilter*> interceptors;
	XMPPConnection * connection;


};

#endif
